#pragma once

namespace AVUI {
    class FrameworkObject;
    class FrameworkElement;
    class FrameworkContentElement;
    typedef TArray< TRefCountedPtr<Object> > ObjectArray;
    typedef ItemStructList< TRefCountedPtr<DependencyObject> > DependencyObjectList;
    class FrameworkElementFactory;

    class BroadcastEventHelper
    {
    public:
#pragma region Internal Methods

        static void AddHasLoadedChangeHandlerFlagInAncestry(DependencyObject* pDO);
        static void AddLoadedCallback(DependencyObject* pDO, DependencyObject* pLogicalParent);
        static void AddOrRemoveHasLoadedChangeHandlerFlag(DependencyObject* pDO, DependencyObject* pOldParent, DependencyObject* pNewParent);
        static void AddUnloadedCallback(DependencyObject* pDO, DependencyObject* pLogicalParent);
        static void BroadcastLoadedEvent(Object* pRoot, Object* pArg);
        static void BroadcastLoadedOrUnloadedEvent(DependencyObject* pDO, DependencyObject* pOldParent, DependencyObject* pNewParent);
        static void BroadcastLoadedSynchronously(DependencyObject* pRootDO, bool isLoaded);
        static void BroadcastUnloadedEvent(Object* pRoot, Object* pArg);
        static void BroadcastUnloadedSynchronously(DependencyObject* pRootDO, bool isLoaded);
        static TRefCountedPtr<FrameworkElementFactory> GetFEFTreeRoot(DependencyObject* pTemplatedParent);
        static bool IsParentLoaded(DependencyObject* pDO);
        static void RemoveHasLoadedChangeHandlerFlagInAncestry(DependencyObject* pDO);
        static void RemoveLoadedCallback(DependencyObject* pDO, ObjectArray* pLoadedPending);
        static void RemoveUnloadedCallback(DependencyObject* pDO, ObjectArray* pUnloadedPending);

#pragma endregion Internal Methods
    private:
#pragma region Private Methods

        struct BroadcastEventData
        {
            BroadcastEventData() { }
            BroadcastEventData(DependencyObject* pRoot, RoutedEvent* pEvent, DependencyObjectList* pRoute) : Root(pRoot), RoutedEvent(pEvent), EventRoute(pRoute) { }

            TRefCountedPtr<DependencyObject> Root;
            RoutedEvent* RoutedEvent;
            TRefCountedPtr<DependencyObjectList> EventRoute;
        };

        static bool AreThereLoadedChangeHandlersInSubtree(FrameworkObject* pFO);
        static void BroadcastEvent(DependencyObject* pRoot, RoutedEvent* pRoutedEvent);
        static void FireLoadedOnDescendentsHelper(DependencyObject* pDO);
        static void FireUnloadedOnDescendentsHelper(DependencyObject* pDO);
        static bool IsLoadedHelper(DependencyObject* pDO);
        static bool OnBroadcastCallback(DependencyObject* pDO, BroadcastEventData data);
        static bool SubtreeHasLoadedChangeHandlerHelper(DependencyObject* pDO);
        static void UpdateHasLoadedChangeHandlerFlagInAncestry(DependencyObject* pDO, bool addHandler);
        static void UpdateIsLoadedCache(FrameworkContentElement* pFCE, DependencyObject* pParent);
        static void UpdateIsLoadedCache(FrameworkElement* pFE, DependencyObject* pParent);

#pragma endregion Private Methods

    };

};


